

<!DOCTYPE html>
<html lang="zh-CN" color-mode=light>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>java并发 - 唱跳rap</title>
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
  <meta name="google" content="notranslate" />
  
  <meta name="description" content="JUC并行并发的区别
并行是同一时刻做多件事情，并发是...">
  <meta name="author" content="东子">
  <link rel="icon" href="/images/icons/icon-29.png" type="image/png" sizes="16x16">
  <link rel="icon" href="/images/icons/icon-29@2x.png" type="image/png" sizes="32x32">
  <link rel="apple-touch-icon" href="/images/icons/icon-1024.png" sizes="180x180">
  <meta rel="mask-icon" href="/images/icons/stun-logo.svg" color="#333333">
  
    <meta rel="msapplication-TileImage" content="/images/icons/icon-1024.png">
    <meta rel="msapplication-TileColor" content="#000000">
  

  
<link rel="stylesheet" href="/css/style.css">


  
    
<link rel="stylesheet" href="https://at.alicdn.com/t/font_1445822_p6ry5n7lrr.css">

  

  
    
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css">

  

  
    
      
        
        
<link rel="stylesheet" href="https://cdn.bootcss.com/highlight.js/9.18.1/styles/xcode.min.css" name="highlight-style" mode="light">

      
        
        
<link rel="stylesheet" href="https://cdn.bootcss.com/highlight.js/9.18.1/styles/solarized-dark.min.css" name="highlight-style" mode="dark">

      
  

  <script>
    var CONFIG = window.CONFIG || {};
    var ZHAOO = window.ZHAOO || {};
    CONFIG = {
      isHome: false,
      fancybox: true,
      pjax: false,
      loading: {
        gif: '',
        lottie: ''
      },
      lazyload: {
        enable: true,
        only_post: 'false',
        loading: {
          gif: '',
          lottie: ''
        }
      },
      donate: {
        enable: false,
        alipay: 'https://pic.izhaoo.com/alipay.jpg',
        wechat: 'https://pic.izhaoo.com/wechat.jpg'
      },
      galleries: {
        enable: false
      },
      fab: {
        enable: true,
        always_show: false
      },
      carrier: {
        enable: true
      },
      daovoice: {
        enable: false
      },
      preview: {
        background: {
          default: '',
          api: 'https://api.paugram.com/bing/'
        },
        motto: {
          default: '我在开了灯的床头下，想问问自己的心啊。',
          typing: true,
          api: 'https://v2.jinrishici.com/one.json',
          data_contents: '["data","content"]'
        },
      },
      qrcode: {
        enable: true,
        type: 'url',
        image: 'https://pic.izhaoo.com/weapp-code.jpg',
      },
      toc: {
        enable: true
      },
      scrollbar: {
        type: 'default'
      },
      notification: {
        enable: false,
        delay: 4500,
        list: '',
        page_white_list: '',
        page_black_list: ''
      },
      search: {
        enable: false,
        path: ''
      }
    }
  </script>

  

  

<meta name="generator" content="Hexo 6.3.0"></head>

<body class="lock-screen">
  <div class="loading" id="loading"></div>
  
    


  <nav class="navbar">
    <div class="left">
      
        <i class="iconfont iconhome j-navbar-back-home"></i>
      
      
        <i class="iconfont iconqrcode j-navbar-qrcode"></i>
      
      
        <i class="iconfont iconmoono" id="color-toggle" color-toggle="light"></i>
      
      
    </div>
    <div class="center">java并发</div>
    <div class="right">
      <i class="iconfont iconmenu j-navbar-menu"></i>
    </div>
    
      <div id="qrcode-navbar"></div>
    
  </nav>

  
  

<nav class="menu">
  <div class="menu-container">
    <div class="menu-close">
      <i class="iconfont iconbaseline-close-px"></i>
    </div>
    <ul class="menu-content"><li class="menu-item">
        <a href="/ " class="underline "> 首页</a>
      </li><li class="menu-item">
        <a href="/archives/ " class="underline "> 归档</a>
      </li><li class="menu-item">
        <a href="/categories/ " class="underline "> 分类</a>
      </li><li class="menu-item">
        <a href="/about/ " class="underline "> 关于</a>
      </li></ul>
    
      <div class="menu-copyright"><p>Powered by <a target="_blank" href="https://gitee.com/comebackearly">东子</a>  | 爷-青结~~</p></div>
    
  </div>
</nav>
  <main id="main">
  <div class="article-wrap">
    <div class="row container">
      <div class="col-xl-3"></div>
      <div class="col-xl-6"><article class="article">
  <div class="wrap">
    <section class="head">
  <img   class="lazyload" data-original="https://10.idqqimg.com/qqcourse_logo_ng/ajNVdqHZLLDpfiageJ021AspmrAdS6FlCPC7JgO4Zgjp5ozCFiaZRJguDIEWicUBnfG9f5bxFdbQcY/600" src=""  draggable="false">
  <div class="head-mask">
    <h1 class="head-title">java并发</h1>
    <div class="head-info">
      <span class="post-info-item"><i class="iconfont iconcalendar"></i>三月 01, 2023</span>
      
      <span class="post-info-item"><i class="iconfont iconfont-size"></i>10854</span>
    </div>
  </div>
</section>
    <section class="main">
      <section class="content">
        
        <h1 id="JUC"><a href="#JUC" class="headerlink" title="JUC"></a>JUC</h1><h2 id="并行并发的区别"><a href="#并行并发的区别" class="headerlink" title="并行并发的区别"></a>并行并发的区别</h2><blockquote>
<p><strong>并行是同一时刻做多件事情</strong>，并发是同一时间段</p>
</blockquote>
<h2 id="创建线程的方式"><a href="#创建线程的方式" class="headerlink" title="创建线程的方式"></a>创建线程的方式</h2><blockquote>
<p>继承Thread类、实现runnable接口实现run方法、实现 Callable接口实现call方法（有返回值）、线程池创建线程</p>
</blockquote>
<ul>
<li><p>继承Thread类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyThread</span> <span class="keyword">extends</span> <span class="title class_">Thread</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyThread...run...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// 创建MyThread对象</span></span><br><span class="line">        <span class="type">MyThread</span> <span class="variable">t1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyThread</span>();</span><br><span class="line">        <span class="type">MyThread</span> <span class="variable">t2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyThread</span>();</span><br><span class="line">        <span class="comment">// 调用start方法启动线程</span></span><br><span class="line">        t1.start();</span><br><span class="line">        t2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>实现Callable接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyCallable</span> <span class="keyword">implements</span> <span class="title class_">Callable</span>&lt;String&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyCallable...call...&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;OK&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span></span><br><span class="line">        <span class="keyword">throws</span> ExecutionException, InterruptedException &#123;</span><br><span class="line">        <span class="comment">// 创建MyCallable对象</span></span><br><span class="line">        <span class="type">MyCallable</span> <span class="variable">mc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyCallable</span>();</span><br><span class="line">        <span class="comment">// 创建F</span></span><br><span class="line">        FutureTask&lt;String&gt; ft = <span class="keyword">new</span> <span class="title class_">FutureTask</span>&lt;String&gt;(mc);</span><br><span class="line">        <span class="comment">// 创建Thread对象</span></span><br><span class="line">        <span class="type">Thread</span> <span class="variable">t1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(ft);</span><br><span class="line">        <span class="type">Thread</span> <span class="variable">t2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(ft);</span><br><span class="line">        <span class="comment">// 调用start方法启动线程</span></span><br><span class="line">        t1.start();</span><br><span class="line">        <span class="comment">// 调用ft的get方法获取执行结果</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> ft.get();</span><br><span class="line">        <span class="comment">// 输出</span></span><br><span class="line">        System.out.println(result);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
<li><p>线程池创建线程</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyExecutors</span> <span class="keyword">implements</span> <span class="title class_">Runnable</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;MyRunnable...run...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// 创建线程池对象</span></span><br><span class="line">        <span class="type">ExecutorService</span> <span class="variable">threadPool</span> <span class="operator">=</span> Executors.newFixedThreadPool(<span class="number">3</span>);</span><br><span class="line">        threadPool.submit(<span class="keyword">new</span> <span class="title class_">MyExecutors</span>());</span><br><span class="line">        <span class="comment">// 关闭线程池</span></span><br><span class="line">        threadPool.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="runable和callable有什么区别"><a href="#runable和callable有什么区别" class="headerlink" title="runable和callable有什么区别"></a>runable和callable有什么区别</h2><ul>
<li><p>Callable接口<strong>call方法有返回值</strong>，是个泛 型，和F<strong>uture、FutureTask</strong>配合可以用来获取异步执行的结果（会阻塞下面方法的执行）</p>
</li>
<li><p>Callable接口的<strong>call()方法允许抛出异常</strong>，Runnable接口的run()方法的异常 只能在内部消化，不能继续上抛</p>
</li>
</ul>
<h2 id="wait和sleep方法的不同"><a href="#wait和sleep方法的不同" class="headerlink" title="wait和sleep方法的不同"></a>wait和sleep方法的不同</h2><p><strong>所属</strong></p>
<ul>
<li><strong>sleep(long) 是 Thread</strong> 的静态方法 而 wait()，<strong>wait(long) 都是 Object</strong> 的成员方法，每个对象都有</li>
</ul>
<p><strong>持锁特性</strong></p>
<ul>
<li>wait 方法的调用必须先获取 <strong>wait 对象的锁（必须放在同步代码块中）</strong>，sleep没有限制</li>
<li><strong>sleep抱着锁睡觉</strong></li>
</ul>
<h2 id="如何停止一个正在运行的线程"><a href="#如何停止一个正在运行的线程" class="headerlink" title="如何停止一个正在运行的线程"></a>如何停止一个正在运行的线程</h2><ul>
<li>使用退出标志，使线程正常退出，也就是当run方法完成后线程终止</li>
<li>使用interrupt方法中断线程：打断阻塞的线程（ sleep，wait，join ）的线程，线程会抛出InterruptedException异常，打断正常的线程，可以根据打断状态来标记是否退出线程</li>
</ul>
<h2 id="java线程有哪些状态，各个状态是怎么流转的"><a href="#java线程有哪些状态，各个状态是怎么流转的" class="headerlink" title="java线程有哪些状态，各个状态是怎么流转的"></a>java线程有哪些状态，各个状态是怎么流转的</h2><ul>
<li>新建（New）: 当线程对象被创建但还未启动时，线程处于新建状态</li>
<li>可运行(Runnable)<ul>
<li>运行状态：线程获得CPU执行时间，正在执行任务。</li>
<li>就绪状态：线程处于可运行状态，等待CPU的分配。</li>
</ul>
</li>
<li>阻塞(Blocked)<ul>
<li>等待阻塞：</li>
<li>同步阻塞</li>
<li>其他阻塞</li>
</ul>
</li>
<li>等待(Waiting)<ul>
<li>等待阻塞</li>
<li>超时等待</li>
</ul>
</li>
<li>被终止(Terminated)：线程的执行完毕或者出现异常导致线程终止，则进入被终止状态</li>
</ul>
<h2 id="Monitor"><a href="#Monitor" class="headerlink" title="Monitor"></a>Monitor</h2><blockquote>
<p><strong>Monitor 被翻译为监视器，是由jvm提供，c++语言实现</strong></p>
</blockquote>
<p>通过反编译上锁的java文件就能看见monitor的相关作用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SyncTest</span> &#123;</span><br><span class="line">	<span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Object</span> <span class="variable">lock</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">	<span class="keyword">static</span> <span class="type">int</span> <span class="variable">counter</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">		<span class="keyword">synchronized</span> (lock) &#123;</span><br><span class="line">			counter++;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img   class="lazyload" data-original="/Java%E5%B9%B6%E5%8F%91/image-20230806160528477.png" src=""  alt="Monitor"></p>
<blockquote>
<p>monitorenter 上锁开始的地方 monitorexit 解锁的地方 其中被monitorenter和monitorexit包围住的指令就是上锁的代码 有两个monitorexit的原因，第二个monitorexit是为了防止锁住的代码抛异常后不 能及时释放锁</p>
</blockquote>
<p>在monitor内部有三个属性，分别是<strong>owner、entrylist、waitset</strong> </p>
<p>其中owner是关联的<strong>获得锁的线程</strong>，并且只能关联一个线程；</p>
<p>entrylist关联的 是<strong>处于阻塞状态的线程</strong>；</p>
<p>waitset关联的是<strong>处于Waiting状态的线程</strong></p>
<h2 id="讲一下synchronized关键字的底层原理"><a href="#讲一下synchronized关键字的底层原理" class="headerlink" title="讲一下synchronized关键字的底层原理"></a>讲一下synchronized关键字的底层原理</h2><blockquote>
<p>Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有 【对象锁】，其它线程再想获取这个【对象锁】时就会阻塞住</p>
</blockquote>
<ul>
<li><p>使用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TicketDemo</span> &#123;</span><br><span class="line">	<span class="keyword">static</span> <span class="type">Object</span> <span class="variable">lock</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">	<span class="type">int</span> <span class="variable">ticketNum</span> <span class="operator">=</span> <span class="number">10</span>;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title function_">getTicket</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">			<span class="keyword">if</span> (ticketNum &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">				<span class="keyword">return</span>;</span><br><span class="line">			&#125;</span><br><span class="line">			System.out.println(Thread.currentThread().getName() +</span><br><span class="line">			<span class="string">&quot;抢到一张票,剩余:&quot;</span> + ticketNum);</span><br><span class="line">			<span class="comment">// 非原子性操作</span></span><br><span class="line">			ticketNum--;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">		<span class="type">TicketDemo</span> <span class="variable">ticketDemo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TicketDemo</span>();</span><br><span class="line">		<span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">20</span>; i++) &#123;</span><br><span class="line">			<span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">				ticketDemo.getTicket();</span><br><span class="line">			&#125;</span><br><span class="line">			).start();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>代码进入synchorized代码块，先让<strong>lock（对象锁）关联的monitor，然后判断 Owner是否有线程持有</strong> </p>
<p>如果没有线程持有，则让当前线程持有，表示该线程获取锁成功 </p>
<p>如果有线程持有，则让当前线程进入entryList进行阻塞，如果Owner持有的线 程已经释放了锁，在EntryList中的线程去竞争锁的持有权（非公平） </p>
<p>如果代码块中调用了wait()方法，则会进去WaitSet中进行等待</p>
</li>
</ul>
<h2 id="JMM-Java内存模型"><a href="#JMM-Java内存模型" class="headerlink" title="JMM Java内存模型"></a>JMM Java内存模型</h2><blockquote>
<p>JMM(Java Memory Model)Java内存模型,是java虚拟机规范中所定义的一种内存模 型。</p>
</blockquote>
<ol>
<li><p>所有的<strong>共享变量都存储于主内存</strong>(计算机的RAM)这里所说的变量指的是实例 变量和类变量。不包含局部变量，因为局部变量是线程私有的，因此不存在 竞争问题。 </p>
</li>
<li><p>每一个<strong>线程还存在自己的工作内存</strong>，保留了被线程使用的 变量的工作<strong>副本</strong>。 </p>
</li>
<li><p>线程对变量的所有的操作**(读，写)都必须在工作内存中完成<strong>，而不能直接读写 主内存中的变量，不同线程之间也不能直接访问对方工作内存中的变量，</strong>线 程间变量的值的传递需要通过主内存完成**。</p>
</li>
</ol>
<h2 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h2><blockquote>
<p>CAS的全称是： Compare And Swap(比较再交换)，它体现的一种<strong>乐观锁</strong>的思想， 在无锁情况下保证线程操作共享数据的<strong>原子性</strong>。</p>
</blockquote>
<p>在JUC（ java.util.concurrent ）包下实现的很多类都用到了CAS操作 AbstractQueuedSynchronizer（<strong>AQS</strong>框架） <strong>AtomicXXX</strong>类</p>
<p>CAS 底层依赖于一个 <strong>Unsafe</strong> 类来直接调用操作系统CAS指令</p>
<h2 id="volatile关键字"><a href="#volatile关键字" class="headerlink" title="volatile关键字"></a>volatile关键字</h2><blockquote>
<p>一旦一个共享变量（类的成员变量、类的静态成员变量）被volatile修饰之后，那么就具备了两层语义</p>
<ul>
<li><strong>保证线程间的可见性</strong></li>
<li><strong>禁止进行指令重排序</strong></li>
</ul>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="type">Boolean</span> <span class="variable">stop</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">	<span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			Thread.sleep(<span class="number">100</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">			e.printStackTrace();</span><br><span class="line">		&#125;</span><br><span class="line">		stop = <span class="literal">true</span>;</span><br><span class="line">		System.out.println(Thread.currentThread().getName()+<span class="string">&quot;：modify stop to true...&quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	,<span class="string">&quot;t1&quot;</span>).start();</span><br><span class="line">	<span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			Thread.sleep(<span class="number">200</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">			e.printStackTrace();</span><br><span class="line">		&#125;</span><br><span class="line">		System.out.println(Thread.currentThread().getName()+<span class="string">&quot;：&quot;</span>+stop);</span><br><span class="line">	&#125;</span><br><span class="line">	,<span class="string">&quot;t2&quot;</span>).start();</span><br><span class="line">	<span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">		<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">		<span class="keyword">while</span> (!stop) &#123;</span><br><span class="line">			i++;</span><br><span class="line">		&#125;</span><br><span class="line">		System.out.println(<span class="string">&quot;stopped... c:&quot;</span>+ i);</span><br><span class="line">	&#125;</span><br><span class="line">	,<span class="string">&quot;t3&quot;</span>).start();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><p><strong>禁止进行指令重排序</strong></p>
<blockquote>
<p>JVM虚拟机中有一个<strong>JIT（即时编译器）</strong>给代码做了优化</p>
</blockquote>
<p>解决方案一：在程序运行的时候加入vm参数-Xint表示<strong>禁用即时编译器</strong>，不推荐，得不偿失（其他程序还要使用） </p>
<p>解决方案二：在修饰stop变量的时候<strong>加上volatile</strong>,当前告诉 jit，不要对 volatile 修饰的变量做优化</p>
</li>
</ul>
<p>用 volatile 修饰共享变量会在读、写共享变量时加入不同的屏障 ，阻止其他读写操作越过屏障，从而达到阻止重排序的效果</p>
<h2 id="什么是AQS"><a href="#什么是AQS" class="headerlink" title="什么是AQS"></a>什么是AQS</h2><blockquote>
<p>全称是 AbstractQueuedSynchronizer，即<strong>抽象队列同步器</strong>。 是多线程中的队列同步器。是一种<strong>锁机制</strong>，它是做为一个基础框架使用的 ，像ReentrantLock、Semaphore都是基于AQS实现的</p>
</blockquote>
<p>Synchronezed和AQS的区别</p>
<table>
<thead>
<tr>
<th>Synchronized</th>
<th>AQS</th>
</tr>
</thead>
<tbody><tr>
<td>关键字，c++ 语言实现</td>
<td>java 语言实现</td>
</tr>
<tr>
<td>悲观锁，自动释放锁</td>
<td>悲观锁，手动开启和关闭</td>
</tr>
<tr>
<td>锁竞争激烈都是重量级锁，性能差</td>
<td>锁竞争激烈的情况下，提供了多种解决方案</td>
</tr>
</tbody></table>
<ul>
<li><p>常见实现类</p>
<ul>
<li><p><strong>ReentrantLock</strong> 阻塞式锁</p>
</li>
<li><p><strong>Semaphore</strong> 信号量 </p>
</li>
<li><p><strong>CountDownLatch</strong> 倒计时锁</p>
</li>
</ul>
</li>
<li><p>AQS内部维护了一个先进先出的<strong>双向队列，队列中存储的排队的线程</strong> </p>
</li>
<li><p>在AQS内部还有一个<strong>属性state</strong>，这个state就相当于是一个资源，默认是0 （无锁状态），如果队列中的有一个线程修改成功了state为1，则当前线 程就相等于获取了<strong>资源</strong> </p>
</li>
<li><p>在对state修改的时候使用的<strong>cas操作</strong>，保证多个线程修改的情况下<strong>原子性</strong></p>
</li>
</ul>
<h2 id="ReetrentLock的实现原理"><a href="#ReetrentLock的实现原理" class="headerlink" title="ReetrentLock的实现原理"></a>ReetrentLock的实现原理</h2><ul>
<li><p>ReentrantLock表示支持<strong>重新进入的锁</strong>，<strong>调用 lock 方 法获取了锁之后， 再次调用 lock，是不会再阻塞</strong> </p>
</li>
<li><p>ReentrantLock主要利用<strong>CAS+AQS</strong>队列来实现 </p>
</li>
<li><p>支持公平锁和非公平锁，在提供的构造器的中无参<strong>默认是非公平锁，</strong>也可 以传参设置为公平锁</p>
</li>
</ul>
<h2 id="Synchronized和Lock有什么区别"><a href="#Synchronized和Lock有什么区别" class="headerlink" title="Synchronized和Lock有什么区别"></a>Synchronized和Lock有什么区别</h2><ul>
<li><p>功能</p>
<ul>
<li>二者<strong>均属于悲观锁</strong>、都具备基本的互斥、同步、锁重入功能 </li>
<li>Lock 提供了许多 synchronized 不具备的功能，例如<strong>公平锁</strong>、<strong>可打断</strong>、<strong>可超时</strong>、多条件变量 Lock 有适合不同场景的实现，如 <strong>ReentrantLock</strong>， <strong>ReentrantReadWriteLock</strong>(读写锁</li>
</ul>
</li>
<li><p>性能</p>
<ul>
<li><strong>在没有竞争时，synchronized 做了很多优化，如偏向锁、轻量级锁，性能不赖</strong> </li>
<li><strong>在竞争激烈时，Lock 的实现通常会提供更好的性能</strong></li>
</ul>
</li>
</ul>
<h2 id="死锁产生的原因是什么"><a href="#死锁产生的原因是什么" class="headerlink" title="死锁产生的原因是什么"></a>死锁产生的原因是什么</h2><ul>
<li>互斥条件</li>
<li>不可剥夺</li>
<li>循环等待</li>
<li>请求和保持</li>
</ul>
<h2 id="ConcurrentHashMap"><a href="#ConcurrentHashMap" class="headerlink" title="ConcurrentHashMap"></a>ConcurrentHashMap</h2><blockquote>
<p>ConcurrentHashMap 是一种线程安全的高效Map集合</p>
</blockquote>
<p>JDK1.7底层采用分段的数组+链表实现 l JDK1.8 采用的数据结构<strong>跟HashMap1.8的结构一样</strong>，数组+链表&#x2F;红黑二叉树</p>
<ul>
<li><p>并发安全</p>
<p>采用 <strong>CAS + Synchronized</strong>来保证并发安全进行实现 </p>
<p>CAS控制数组节点的添加 </p>
<p><strong>synchronized只锁定当前链表或红黑二叉树的首节点</strong>，只要hash不冲突，就不会产生并发的问题 , 效率得到提升</p>
</li>
</ul>
<h2 id="线程池的核心参数，执行流程"><a href="#线程池的核心参数，执行流程" class="headerlink" title="线程池的核心参数，执行流程"></a>线程池的核心参数，执行流程</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">ThreadPoolExecutor</span><span class="params">(<span class="type">int</span> corePoolSize,//核心线程数 </span></span><br><span class="line"><span class="params">                          <span class="type">int</span> maximumPoolSize,//最大线程数</span></span><br><span class="line"><span class="params">                          <span class="type">long</span> keepAliveTime//线程存活时间</span></span><br><span class="line"><span class="params">                          TimeUnit unit, //救急线程时间单位</span></span><br><span class="line"><span class="params">                          BlockingQueue &lt; Runnable &gt; workQueue, //阻塞队列</span></span><br><span class="line"><span class="params">                          ThreadFactory threadFactory,//线程工厂</span></span><br><span class="line"><span class="params">                          RejectedExecutionHandler handler)</span><span class="comment">//拒绝策略</span></span><br></pre></td></tr></table></figure>

<ul>
<li><p>执行流程</p>
<p><img   class="lazyload" data-original="/Java%E5%B9%B6%E5%8F%91/image-20230816112620046.png" src=""  alt="image-20230816112620046"></p>
</li>
<li><p>拒绝策略</p>
<ol>
<li>.AbortPolicy：直接<strong>抛出异常</strong>，默认策略；</li>
<li>CallerRunsPolicy：用<strong>调用者所在的线程</strong>来执行任务；</li>
<li>DiscardOldestPolicy：<strong>丢弃阻塞队列中靠最前</strong>的任务，并执行当前任务</li>
<li>DiscardPlocy: 直接<strong>丢弃任务</strong></li>
</ol>
</li>
</ul>
<h2 id="线程池中常见的阻塞队列"><a href="#线程池中常见的阻塞队列" class="headerlink" title="线程池中常见的阻塞队列"></a>线程池中常见的阻塞队列</h2><blockquote>
<p>workQueue - 当没有空闲核心线程时，新来任务会加入到此队列排队，队列满会创建救急线程执行任务</p>
</blockquote>
<ol>
<li>ArrayBlockingQueue：基于<strong>数组结构</strong>的有界阻塞队列，FIFO。</li>
<li>LinkedBlockingQueue：基于<strong>链表结构</strong>的有界阻塞队列，FIFO。 </li>
<li>DelayedWorkQueue ：是一个<strong>优先级队列</strong>，它可以保证每次出队的任务都是当前队列中<strong>执行时间最靠前</strong>的 </li>
<li>SynchronousQueue：<strong>不存储元素的阻塞队列</strong>，每个插入操作都必须等待一个移出操作。</li>
</ol>
<h2 id="怎么确定核心线程数-公式"><a href="#怎么确定核心线程数-公式" class="headerlink" title="怎么确定核心线程数(公式)"></a>怎么确定核心线程数(公式)</h2><ul>
<li><strong>IO密集</strong>型任务   核心线程数大小设置为2N+1</li>
<li><strong>CPU密集型</strong>任务  核心线程数大小设置为N+</li>
</ul>
<h2 id="线程池的种类有哪些"><a href="#线程池的种类有哪些" class="headerlink" title="线程池的种类有哪些"></a>线程池的种类有哪些</h2><blockquote>
<p>在java.util.concurrent.Executors类中提供了大量创建连接池的静态方法，常见就有四种</p>
</blockquote>
<ul>
<li><p>创建使用固定线程数的线程池</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newFixedThreadPool</span><span class="params">(<span class="type">int</span> nThreads)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(nThreads,</span><br><span class="line">                                  nThreads, </span><br><span class="line">                                  <span class="number">0</span> L, </span><br><span class="line">                                  TimeUnit.MILLISECONDS,</span><br><span class="line">                                  <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span> &lt; Runnable &gt; ());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 核心线程数与最大线程数一样，没有救急线程,阻塞队列是LinkedBlockingQueue，最大容量为Integer.MAX_VALUE</p>
<p>（<strong>适用于任务量已知，相对耗时的任务</strong>）</p>
</li>
<li><p>单线程化的线程池,它只会用唯一的工作线程来执行任 务，保证所有任务按照指定顺序(FIFO)执行</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newSingleThreadExecutor</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">FinalizableDelegatedExecutorService</span>(<span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">1</span>,</span><br><span class="line">                                                                          <span class="number">1</span>,</span><br><span class="line">                                                                          <span class="number">0</span> L,</span><br><span class="line">                                                                          TimeUnit.MILLISECONDS,</span><br><span class="line">                                                                          <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span> &lt; Runnable &gt; ()));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>适用于按照顺序执行的任务</strong></p>
</li>
<li><p>可缓存线程池</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newCachedThreadPool</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">0</span>, </span><br><span class="line">                                  Integer.MAX_VALUE, </span><br><span class="line">                                  <span class="number">60</span> L, </span><br><span class="line">                                  TimeUnit.SECONDS,</span><br><span class="line">                                  <span class="keyword">new</span> <span class="title class_">SynchronousQueue</span> &lt; Runnable &gt; ());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>核心线程数为0 l 最大线程数是Integer.MAX_VALUE l 阻塞队列为SynchronousQueue:不存储元素的阻塞队列，每个插入操作都必须等待一个移出操作。</p>
<p><strong>适合任务数比较密集，但每个任务执行时间较短的情况</strong></p>
</li>
<li><p>newScheduledThreadPool：<strong>可以执行延迟任务的线程池，支持定时及周期性任务执行</strong></p>
</li>
</ul>
<h2 id="为什么不建议用Executors创建线程池"><a href="#为什么不建议用Executors创建线程池" class="headerlink" title="为什么不建议用Executors创建线程池"></a>为什么不建议用Executors创建线程池</h2><p><strong>FixedThreadPool 和singleThreadPool 和 CachaedThreadPool 的阻塞队列的长度都是Integer.MaxLengh(),会导致OOM</strong></p>
<h2 id="CountDownLatch-Future"><a href="#CountDownLatch-Future" class="headerlink" title="CountDownLatch , Future"></a>CountDownLatch , Future</h2><blockquote>
<p>CountDownLatch（闭锁&#x2F;倒计时锁）用来进行线程同步协作，等待所有线程完成倒计时（一个或者多个线程，等待其他 多个线程完成某件事情之后才能执行）</p>
</blockquote>
<ul>
<li><strong>使用场景</strong>（数据汇总）</li>
</ul>
<p><img   class="lazyload" data-original="/Java%E5%B9%B6%E5%8F%91/image-20230816114351705.png" src=""  alt="image-20230816114351705"></p>
<p>在实际开发的过程中，难免需要调用多个接口来汇总数据，如果所有接口（或部分接口）的没有依赖关系，就可以 使用线程池+future来提升性能</p>
<h2 id="怎么控制某个方法允许并发访问的线程数量"><a href="#怎么控制某个方法允许并发访问的线程数量" class="headerlink" title="怎么控制某个方法允许并发访问的线程数量"></a>怎么控制某个方法允许并发访问的线程数量</h2><blockquote>
<p>Semaphore 信号量，是JUC包下的一个工具类，底层是<strong>AQS，</strong>我们可以通过其限制执行的线程数量,通常用于那些资源有明确访问数量限制的场景，常用于限流</p>
</blockquote>
<ol>
<li><p>创建Semaphore对象，可以给一个容量 </p>
</li>
<li><p>acquire()可以请求一个信号量，这时候的信号量个数-1 </p>
</li>
<li><p>release()释放一个信号量，此时信号量个数+1</p>
</li>
</ol>
<ul>
<li><p>限流</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. 创建 semaphore 对象</span></span><br><span class="line"><span class="type">Semaphore</span> <span class="variable">semaphore</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Semaphore</span>(<span class="number">3</span>);</span><br><span class="line"><span class="comment">// 2. 10个线程同时运行</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Thread</span>(() - &gt; &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 3. 获取许可</span></span><br><span class="line">            semaphore.acquire();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;running...&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;end...&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="comment">// 4. 释放许可</span></span><br><span class="line">            semaphore.release();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;).start();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="说说你对ThreadLocal的理解"><a href="#说说你对ThreadLocal的理解" class="headerlink" title="说说你对ThreadLocal的理解"></a>说说你对ThreadLocal的理解</h2><ol>
<li><p>ThreadLocal 可以实现【资源对象】的<strong>线程隔离</strong>，让每个线程各用各的【资源对象】 ，避免争用引发的线程安全问题</p>
</li>
<li><p>ThreadLocal 同时实现了线程内的<strong>资源共享</strong> </p>
</li>
<li><p>每个线程内有一个 <strong>ThreadLocalMap</strong> 类型的成员变量，用来存储资源对象 a)调用 set 方法，就是以 ThreadLocal 自己作为 key，资源对象作为 value，放入当前线 程的 ThreadLocalMap 集合中 b)调用 get 方法，就是以 ThreadLocal 自己作为 key，到当前线程中查找关联的资源值 c)调用 remove 方法，就是以 ThreadLocal 自己作为 key，移除当前线程关联的资源值</p>
</li>
<li><p>ThreadLocal<strong>内存泄漏</strong>问题 ThreadLocalMap 中的 key 是弱引用，值为强引用；key 会被GC 释放内存，关联 value 的 内存并不会释放。建议主动 remove 释放 key，value</p>
</li>
</ol>

      </section>
      <section class="extra">
        
          <ul class="copyright">
  
    <li><strong>本文作者：</strong>东子</li>
    <li><strong>本文链接：</strong><a href="https://comebackearly.gitee.io/2023/03/01/Java%E5%B9%B6%E5%8F%91/index.html" title="https:&#x2F;&#x2F;comebackearly.gitee.io&#x2F;2023&#x2F;03&#x2F;01&#x2F;Java%E5%B9%B6%E5%8F%91&#x2F;index.html">https:&#x2F;&#x2F;comebackearly.gitee.io&#x2F;2023&#x2F;03&#x2F;01&#x2F;Java%E5%B9%B6%E5%8F%91&#x2F;index.html</a></li>
    <li><strong>版权声明：</strong>本博客所有文章均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" title="BY-NC-SA" target="_blank" rel="noopener">BY-NC-SA</a> 许可协议，转载请注明出处！</li>
  
</ul>
        
        
        
        
  <nav class="nav">
    <a href="/2023/05/10/io%E6%B5%81/"><i class="iconfont iconleft"></i>javaIO流</a>
    <a href="/2023/01/10/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">设计模式<i class="iconfont iconright"></i></a>
  </nav>

      </section>
      
        <section class="comments">
  
    <div class="btn" id="comments-btn">查看评论</div>
  
  
<div id="valine"></div>
<script defer src="//unpkg.com/valine/dist/Valine.min.js"></script>
<script>
  window.onload = function () {
    var loadValine = function () {
      new Valine({
        el: '#valine',
        app_id: "833C0IwLe9o8QE1pN25Mv59F-gzGzoHsz",
        app_key: "YLQZdn7egrZOmJnwr6YFEw0y",
        placeholder: "雁过留痕",
        avatar: "mp",
        pageSize: "10",
        lang: "zh-CN",
      });
    }
    if ( true ) {
      $("#comments-btn").on("click", function () {
        $(this).hide();
        loadValine();
      });
    } else {
      loadValine();
    }
  };
</script>

</section>
      
    </section>
  </div>
</article></div>
      <div class="col-xl-3">
        
          
  <aside class="toc-wrap">
    <h3 class="toc-title">文章目录：</h3>
    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#JUC"><span class="toc-text">JUC</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B9%B6%E8%A1%8C%E5%B9%B6%E5%8F%91%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">并行并发的区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9B%E5%BB%BA%E7%BA%BF%E7%A8%8B%E7%9A%84%E6%96%B9%E5%BC%8F"><span class="toc-text">创建线程的方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#runable%E5%92%8Ccallable%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB"><span class="toc-text">runable和callable有什么区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#wait%E5%92%8Csleep%E6%96%B9%E6%B3%95%E7%9A%84%E4%B8%8D%E5%90%8C"><span class="toc-text">wait和sleep方法的不同</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E5%81%9C%E6%AD%A2%E4%B8%80%E4%B8%AA%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E7%BA%BF%E7%A8%8B"><span class="toc-text">如何停止一个正在运行的线程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#java%E7%BA%BF%E7%A8%8B%E6%9C%89%E5%93%AA%E4%BA%9B%E7%8A%B6%E6%80%81%EF%BC%8C%E5%90%84%E4%B8%AA%E7%8A%B6%E6%80%81%E6%98%AF%E6%80%8E%E4%B9%88%E6%B5%81%E8%BD%AC%E7%9A%84"><span class="toc-text">java线程有哪些状态，各个状态是怎么流转的</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Monitor"><span class="toc-text">Monitor</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%AE%B2%E4%B8%80%E4%B8%8Bsynchronized%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86"><span class="toc-text">讲一下synchronized关键字的底层原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JMM-Java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B"><span class="toc-text">JMM Java内存模型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#CAS"><span class="toc-text">CAS</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#volatile%E5%85%B3%E9%94%AE%E5%AD%97"><span class="toc-text">volatile关键字</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AFAQS"><span class="toc-text">什么是AQS</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ReetrentLock%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-text">ReetrentLock的实现原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Synchronized%E5%92%8CLock%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB"><span class="toc-text">Synchronized和Lock有什么区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%AD%BB%E9%94%81%E4%BA%A7%E7%94%9F%E7%9A%84%E5%8E%9F%E5%9B%A0%E6%98%AF%E4%BB%80%E4%B9%88"><span class="toc-text">死锁产生的原因是什么</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ConcurrentHashMap"><span class="toc-text">ConcurrentHashMap</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8F%82%E6%95%B0%EF%BC%8C%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-text">线程池的核心参数，执行流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97"><span class="toc-text">线程池中常见的阻塞队列</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%8E%E4%B9%88%E7%A1%AE%E5%AE%9A%E6%A0%B8%E5%BF%83%E7%BA%BF%E7%A8%8B%E6%95%B0-%E5%85%AC%E5%BC%8F"><span class="toc-text">怎么确定核心线程数(公式)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E7%A7%8D%E7%B1%BB%E6%9C%89%E5%93%AA%E4%BA%9B"><span class="toc-text">线程池的种类有哪些</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BB%BA%E8%AE%AE%E7%94%A8Executors%E5%88%9B%E5%BB%BA%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="toc-text">为什么不建议用Executors创建线程池</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#CountDownLatch-Future"><span class="toc-text">CountDownLatch , Future</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%8E%E4%B9%88%E6%8E%A7%E5%88%B6%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%E5%85%81%E8%AE%B8%E5%B9%B6%E5%8F%91%E8%AE%BF%E9%97%AE%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%95%B0%E9%87%8F"><span class="toc-text">怎么控制某个方法允许并发访问的线程数量</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%AF%B4%E8%AF%B4%E4%BD%A0%E5%AF%B9ThreadLocal%E7%9A%84%E7%90%86%E8%A7%A3"><span class="toc-text">说说你对ThreadLocal的理解</span></a></li></ol></li></ol>
  </aside>

        
      </div>
    </div>
  </div>
</main>
  

<footer class="footer">
  <div class="footer-social"><a 
        href="tencent://message/?Menu=yes&uin=2911890696 "
        target="_blank"
        class="footer-social-item"
        onMouseOver="this.style.color= '#12B7F5'" 
        onMouseOut="this.style.color='#33333D'">
          <i class="iconfont  iconQQ "></i>
      </a><a 
        href="javascript:; "
        target="_blank"
        class="footer-social-item"
        onMouseOver="this.style.color= '#09BB07'" 
        onMouseOut="this.style.color='#33333D'">
          <i class="iconfont  iconwechat-fill "></i>
      </a><a 
        href="https://github.com/nuban "
        target="_blank"
        class="footer-social-item"
        onMouseOver="this.style.color= '#9f7be1'" 
        onMouseOut="this.style.color='#33333D'">
          <i class="iconfont  icongithub-fill "></i>
      </a></div>
  
    <div class="footer-copyright"><p>Powered by <a target="_blank" href="https://gitee.com/comebackearly">东子</a>  | 爷-青结~~</p></div>
  
  <link rel="stylesheet" href="/dist/APlayer.min.css">
  <div id="aplayer"></div>
  <script type="text/javascript" src="/dist/APlayer.min.js"></script>
  <script type="text/javascript" src="/dist/music.js"></script>
  
</footer>
  
      <div class="fab fab-plus">
    <i class="iconfont iconplus"></i>
  </div>
  
  
  
  <div class="fab fab-up">
    <i class="iconfont iconcaret-up"></i>
  </div>
  
  
  
    
<script src="/js/color-mode.js"></script>

  
  
</body>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>





  
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"></script>




  
<script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js"></script>






  
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>




<script src="/js/utils.js"></script>
<script src="/js/script.js"></script>







  <script>
    (function () {
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
      } else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
      }
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
    })();
  </script>



  <script defer src='https://hm.baidu.com/hm.js?dda12e485d1b1d3113db8147f482111c'></script>











</html>